25.4 Ein eigenes Steuerelement entwerfen  
Ob Sie ein Benutzersteuerelement entwerfen und sich dabei der Vorlage UserControl bedienen oder ob Sie sich an den objektorientierten Ansatz erinnern und ein vorhandenes Steuerelement ableiten, in einem Punkt gleichen sich beide Verfahren: Die Grundlage bildet immer mindestens ein vorhandenes Steuerelement.
Natürlich können Sie auch ein Steuerelement entwickeln, das nicht auf eine vorhandene Basis aufbaut. Dann müssen Sie aber auch alles selbst in die Hand nehmen und codieren, womit insbesondere das vollständige Neuzeichnen gemeint ist.
Auch wenn selbst entworfene Steuerelemente nicht in irgendeiner Form auf vorhandene Steuerelemente aufbauen, wird uns ein nicht unwesentlicher Teil der Codierung abgenommen, denn alle Steuerelemente haben eine gemeinsame Basisklasse, in der die elementarsten Eigenschaften und Methoden vordefiniert sind: Control. Um davon zu profitieren, leiten Sie ganz einfach die Klasse ab. Angenommen, das neue Steuerelement soll ein Label sein, das die Beschriftung in vertikaler Ausrichtung anzeigt, könnte die Klasse folgendermaßen definiert sein:
| Public Class VerticalLabel
|
| Ingherits Control
|
| ...
|
| End Class
|
Die Ableitung von Control bewirkt, dass ein leerer Clientbereich auf der Form gezeichnet wird. Da das Steuerelement aber eine grafische Präsentation haben soll, in unserem Beispiel eine vertikale Textausrichtung, müssen wir diese selbst zeichnen. Wir wissen, dass das Paint-Ereignis immer dann ausgelöst wird, wenn eine Komponente sich selbst neu zeichnen muss. Daher überschreiben wir die von Control geerbte Methode OnPaint, welche die installierten Ereignishandler aufruft, und implementieren darin den erforderlichen Code.
Beim Zeichnen müssen wir berücksichtigen, dass die Beschriftung von unten nach oben ausgerichtet ist. Das bedeutet, wir müssen sie drehen. In Kapitel 22 haben Sie die dazu passende Methode kennen gelernt: RotateTransform, deren positive Drehrichtung im Uhrzeigersinn ist. Doch um welchen Punkt soll gedreht werden? Wollen wir die Schrift von unten nach oben ausrichten, ist der Drehpunkt der linke untere Eckpunkt des Steuerelements. Da alle Komponenten links oben ihren vordefinierten Ursprungspunkt haben, ist dessen Verschiebung mit TranslateTransform unumgänglich.
Das Neuzeichnen des Benutzersteuerelements ist auch notwendig, wenn zur Entwurfszeit die Größe eines VerticalLabel-Objekts in seiner Form verändert wird. Deshalb wird mittels Programmcode durch Aufruf von Invalidate im Resize-Ereignishandler das Paint-Ereignis ausgelöst. Bei der Instanziierung mittels Doppelklick in der Toolbox zeichnen sich Steuerelemente in einer definierten Standardgröße in ihren Container. Diese legen wir in der Methode InitializeComponent fest. Sie sei 25 Pixel breit und 100 Pixel hoch.
Als wir weiter oben EllipseLabel entwickelt hatten, konnten wir den Text im konstituierenden Label-Steuerelement speichern. Diese Möglichkeit haben wir jetzt nicht. Stattdessen müssen wir ein Feld auf Klassenebene deklarieren, das diese Aufgabe übernimmt. Das Feld soll lblText heißen und ist, um den Konventionen eines guten objektorientierten Ansatzes zu folgen, private deklariert. Die Eigenschaftsmethode Text veröffentlicht das Feld.
| ' ----------------------------------------------------------
|
| ' Beispiel: ...\Kapitel 25\VerticalLabel
|
| ' ----------------------------------------------------------
|
| Imports System.Drawing
|
| Imports System.Windows.Forms
|
| Public Class VerticalLabel
|
| Inherits Control
|
| Dim lblText As String
|
| Public Sub New()
|
| InitializeComponent()
|
| End Sub
|
| Private Sub InitializeComponent()
|
| ' Festlegen der Initialisierungsgröße
|
| Me.Size = New Size(25, 100)
|
| AddHandler Me.Resize, AddressOf VerticalLabel_Resize
|
| End Sub
|
| Private Sub VerticalLabel_Resize(ByVal sender As Object, _
|
| ByVal e As EventArgs)
|
| Invalidate()
|
| End Sub
|
| Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
|
| Dim lblColor As Color = Color.Empty
|
| Dim controlWidth As Single
|
| Dim controlHeight As Single
|
| Dim transformX As Single
|
| Dim transformY As Single
|
| Dim backcolor As SolidBrush = New SolidBrush(lblColor)
|
| Dim forecolor As SolidBrush = _
|
| New SolidBrush(MyBase.ForeColor)
|
| Dim borderPen As Pen = New Pen(lblColor, 0)
|
| MyBase.OnPaint(e)
|
| controlWidth = Me.Size.Width
|
| controlHeight = Me.Size.Height
|
| ' Rahmen zeichnen
|
| e.Graphics.DrawRectangle(borderPen, 0, 0, _
|
| controlWidth, controlHeight)
|
| e.Graphics.FillRectangle(backcolor, 0, 0, _
|
| controlWidth, controlHeight)
|
| transformX = 0
|
| transformY = controlHeight
|
| ' Ursprungspunkt versetzen
|
| e.Graphics.TranslateTransform(transformX, transformY)
|
| ' Steuerelement drehen
|
| e.Graphics.RotateTransform(270)
|
| ' Text in das Steuerelement zeichnen
|
| e.Graphics.DrawString(lblText, Me.Font, forecolor, 0, 0)
|
| End Sub
|
| ' Veröffentlichen der Eigenschaft 'Text'
|
| Public Overrides Property Text() As String
|
| Get
|
| Return lblText
|
| End Get
|
| Set(ByVal value As String)
|
| lblText = value
|
| Invalidate()
|
| End Set
|
| End Property
|
| End Class
|
Für unser Beispiel soll das genügen. Natürlich ließe sich das Steuerelement auch noch durch weitere Eigenschaften, Methoden und Ereignisse verfeinern. Für uns soll das aber vollkommen ausreichend sein.
|